<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="../Universal.css">
</head>
<body>
    
    <div id="cnblogs_post_body" class="blogpost-body">
        <h2>什么是JDBC</h2>
    <p>JDBC（Java DataBase Connectivity）就是Java数据库连接，说白了就是用Java语言来操作数据库。原来我们操作数据库是在控制台使用SQL语句来操作数据库，JDBC是用Java语言向数据库发送SQL语句。</p>
    <h3>JDBC原理</h3>
    <p>早期SUN公司的天才们想编写一套可以连接天下所有数据库的API，但是当他们刚刚开始时就发现这是不可完成的任务，因为各个厂商的数据库服务器差异太大了。后来SUN开始与数据库厂商们讨论，最终得出的结论是，由SUN提供一套访问数据库的规范（就是一组接口），并提供连接数据库的协议标准，然后各个数据库厂商会遵循SUN的规范提供一套访问自己公司的数据库服务器的API出现。SUN提供的规范命名为JDBC，而各个厂商提供的，遵循了JDBC规范的，可以访问自己数据库的API被称之为驱动！<br>JDBC是接口，而JDBC驱动才是接口的实现，没有驱动无法完成数据库连接！每个数据库厂商都有自己的驱动，用来连接自己公司的数据库。<br>当然还有第三方公司专门为某一数据库提供驱动，这样的驱动往往不是开源免费的！<br>JDBC核心类（接口）介绍<br>JDBC中的核心类有：DriverManager、Connection、Statement，和ResultSet！<br>DriverManger（驱动管理器）的作用有两个：</p>
    <ul>
    <li>注册驱动：这可以让JDBC知道要使用的是哪个驱动；</li>
    <li>获取Connection：如果可以获取到Connection，那么说明已经与数据库连接上了。</li>
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    </ul>
    <p>Connection对象表示连接，与数据库的通讯都是通过这个对象展开的。Connection最为重要的一个方法就是用来获取Statement对象；<br>Statement是用来向数据库发送SQL语句的，这样数据库就会执行发送过来的SQL语句<br>void executeUpdate(String sql)：执行更新操作（insert、update、delete等）；<br>ResultSet executeQuery(String sql)：执行查询操作，数据库在执行查询后会把查询结果，查询结果就是ResultSet；<br>ResultSet对象表示查询结果集，只有在执行查询操作后才会有结果集的产生。结果集是一个二维的表格，有行有列。操作结果集要学习移动ResultSet内部的“行光标”，以及获取当前行上的每一列上的数据：</p>
    <pre>boolean next()：使“行光标”移动到下一行，并返回移动后的行是否存在；<br>XXX getXXX(int col)：获取当前行指定列上的值，参数就是列数，列数从1开始，而不是0。</pre>
    <h3>下面开始编写第一个JDBC程序</h3>
    <p><span style="line-height: 1.5">1、导入mysql数据库的驱动jar包：</span>&nbsp;<span class="cnblogs_code">mysql<span style="color: rgba(128, 128, 128, 1)">-</span>connector<span style="color: rgba(128, 128, 128, 1)">-</span>java<span style="color: rgba(128, 128, 128, 1)">-</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">5.1</span>.<span style="color: rgba(128, 0, 0, 1); font-weight: bold">39</span><span style="color: rgba(128, 128, 128, 1)">-</span>bin.jar；</span>&nbsp;</p>
    <p>2、注册驱动<br>看清楚了，注册驱动就只有一句话：&nbsp;<span class="cnblogs_code">Class.forName(“com.mysql.jdbc.Driver”)</span>&nbsp;，</p>
    <p>下面的内容都是对这句代码的解释。今后我们的代码中，与注册驱动相关的代码只有这一句。</p>
    <pre>DriverManager类的registerDriver()方法的参数是java.sql.Driver，但java.sql.Driver是一个接口，实现类由mysql驱动来提供，mysql驱动中的java.sql.Driver接口的实现类为com.mysql.jdbc.Driver！那么注册驱动的代码如下：<br>DriverManager.registerDriver(new com.mysql.jdbc.Driver());</pre>
    <p>上面代码虽然可以注册驱动，但是出现硬编码（代码依赖mysql驱动jar包），如果将来想连接Oracle数据库，那么必须要修改代码的。并且其实这种注册驱动的方式是注册了两次驱动！<br>JDBC中规定，驱动类在被加载时，需要自己“主动”把自己注册到DriverManger中，下面我们来看看com.mysql.jdbc.Driver类的源代码：<br>com.mysql.jdbc.Driver.java</p>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> class Driver extends NonRegisteringDriver implements java.sql.Driver {
        static {
            try {
                java.sql.DriverManager.registerDriver(new Driver());
            } catch (SQLException E) {
                throw new RuntimeException("Can</span><span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(255, 0, 0, 1)">t register driver!");
            }
        }
    ……
    }</span></pre>
    </div>
    <p>com.mysql.jdbc.Driver类中的static块会创建本类对象，并注册到DriverManager中。这说明只要去加载com.mysql.jdbc.Driver类，那么就会执行这个static块，从而也就会把com.mysql.jdbc.Driver注册到DriverManager中，所以可以把注册驱动类的代码修改为加载驱动类。<br>3、获取连接<br>获取连接需要两步，一是使用DriverManager来注册驱动，二是使用DriverManager来获取Connection对象。获取连接的也只有一句代码：&nbsp;DriverManager.getConnection(url,username,password)，&nbsp;</p>
    <p>其中username和password是登录数据库的用户名和密码。url查对复杂一点，它是用来找到要连接数据库“网址”，就好比你要浏览器中查找百度时，也需要提供一个url。下面是mysql的url：<br>jdbc:mysql://localhost:3306/mydb1<br>JDBC规定url的格式由三部分组成，每个部分中间使用冒号分隔。</p>
    <ul>
    <li>第一部分是jdbc，这是固定的；</li>
    <li>第二部分是数据库名称，那么连接mysql数据库，第二部分当然是mysql了；</li>
    <li>第三部分是由数据库厂商规定的，我们需要了解每个数据库厂商的要求，mysql的第三部分分别由数据库服务器的IP地址（localhost）、端口号（3306），以及DATABASE名称(mydb1)组成。</li>
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    </ul>
    <p>下面是获取连接的语句：</p>
    <div class="cnblogs_code">
    <pre>Connection con <span style="color: rgba(128, 128, 128, 1)">=</span> DriverManager.getConnection(“jdbc:mysql:<span style="color: rgba(128, 128, 128, 1)">//</span>localhost:<span style="color: rgba(128, 0, 0, 1); font-weight: bold">3306</span><span style="color: rgba(128, 128, 128, 1)">/</span>web08”,”root”,”root”);</pre>
    </div>
    <p><span style="line-height: 1.5">还可以在url中提供参数：</span></p>
    <pre>jdbc:mysql://localhost:3306/web08?useUnicode=true&amp;characterEncoding=UTF8<br>useUnicode参数指定这个连接数据库的过程中，使用的字节集是Unicode字节集；<br>characherEncoding参数指定连上连接数据库的过程中，使用的字节集编码为UTF-8编码。请注意，mysql中指定UTF-8编码是给出的是UTF8，而不是UTF-8。要小心了！</pre>
    <p>4、 获取Statement<br>在得到Connectoin之后，说明已经与数据库连接上了，下面是通过Connection获取Statement对象的代码：</p>
    <div class="cnblogs_code">
    <pre>Statement stmt <span style="color: rgba(128, 128, 128, 1)">=</span> con.createStatement();</pre>
    </div>
    <p><span style="line-height: 1.5">Statement是用来向数据库发送要执行的SQL语句的！</span></p>
    <p>5、发送SQL查询语句</p>
    <div class="cnblogs_code">
    <pre>String sql <span style="color: rgba(128, 128, 128, 1)">=</span> “<span style="color: rgba(0, 0, 255, 1)">select</span> <span style="color: rgba(128, 128, 128, 1)">*</span> <span style="color: rgba(0, 0, 255, 1)">from</span> <span style="color: rgba(255, 0, 255, 1)">user</span><span style="color: rgba(0, 0, 0, 1)">”;
    ResultSet rs </span><span style="color: rgba(128, 128, 128, 1)">=</span> stmt.executeQuery(sql);</pre>
    </div>
    <p><span style="line-height: 1.5">请注意，执行查询使用的不是executeUpdate()方法，而是executeQuery()方法。executeQuery()方法返回的是ResultSet，ResultSet封装了查询结果，我们称之为结果集。</span></p>
    <p>6、读取结果集中的数据<br>ResultSet就是一张二维的表格，它内部有一个“行光标”，光标默认的位置在“第一行上方”，我们可以调用rs对象的next()方法把“行光标”向下移动一行，当第一次调用next()方法时，“行光标”就到了第一行记录的位置，这时就可以使用ResultSet提供的getXXX(int col)方法来获取指定列的数据了。</p>
    <div class="cnblogs_code">
    <pre>rs.<span style="color: rgba(0, 0, 255, 1)">next</span>();<span style="color: rgba(128, 128, 128, 1)">//</span><span style="color: rgba(0, 0, 0, 1)">光标移动到第一行
    rs.getInt(</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">1</span>);<span style="color: rgba(128, 128, 128, 1)">//</span>获取第一行第一列的数据</pre>
    </div>
    <p><span style="line-height: 1.5">当你使用rs.getInt(1)方法时，你必须可以肯定第1列的数据类型就是int类型，如果你不能肯定，那么最好使用rs.getObject(1)。在ResultSet类中提供了一系列的getXXX()方法，比较常用的方法有：</span></p>
    <div class="cnblogs_code">
    <pre>Object getObject(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> col)
    String getString(</span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> col)
    </span><span style="color: rgba(0, 0, 255, 1)">int</span> getInt(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> col)
    </span><span style="color: rgba(0, 0, 255, 1)">double</span> getDouble(<span style="color: rgba(0, 0, 255, 1)">int</span> col)</pre>
    </div>
    <p><span style="line-height: 1.5">7、关闭</span></p>
    <p>与IO流一样，使用后的东西都需要关闭！关闭的顺序是先得到的后关闭，后得到的先关闭。</p>
    <div class="cnblogs_code">
    <pre>rs.<span style="color: rgba(0, 0, 255, 1)">close</span><span style="color: rgba(0, 0, 0, 1)">();
    stmt.</span><span style="color: rgba(0, 0, 255, 1)">close</span><span style="color: rgba(0, 0, 0, 1)">();
    con.</span><span style="color: rgba(0, 0, 255, 1)">close</span>();</pre>
    </div>
    <p><span style="line-height: 1.5">8、完成查询操作代码&nbsp;</span></p>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> static Connection getConnection() throws Exception {
            Class.forName("com.mysql.jdbc.Driver");
            String url </span><span style="color: rgba(128, 128, 128, 1)">=</span> "jdbc:mysql:<span style="color: rgba(128, 128, 128, 1)">//</span>localhost:<span style="color: rgba(128, 0, 0, 1); font-weight: bold">3306</span><span style="color: rgba(128, 128, 128, 1)">/</span><span style="color: rgba(0, 0, 0, 1)">web08";
            </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> DriverManager.getConnection(url, "root", "root");
        }
        </span><span style="color: rgba(0, 128, 0, 1)">@Test</span>
        <span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> void query() throws Exception {
            Connection con </span><span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(0, 0, 0, 1)"> getConnection();
            Statement stmt </span><span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(0, 0, 0, 1)"> con.createStatement();
            String sql </span><span style="color: rgba(128, 128, 128, 1)">=</span> "<span style="color: rgba(0, 0, 255, 1)">select</span> <span style="color: rgba(128, 128, 128, 1)">*</span> <span style="color: rgba(0, 0, 255, 1)">from</span> <span style="color: rgba(255, 0, 255, 1)">user</span><span style="color: rgba(0, 0, 0, 1)">";
            ResultSet rs </span><span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(0, 0, 0, 1)"> stmt.executeQuery(sql);
            </span><span style="color: rgba(0, 0, 255, 1)">while</span>(rs.<span style="color: rgba(0, 0, 255, 1)">next</span><span style="color: rgba(0, 0, 0, 1)">()) {
                String username </span><span style="color: rgba(128, 128, 128, 1)">=</span> rs.getString(<span style="color: rgba(128, 0, 0, 1); font-weight: bold">1</span><span style="color: rgba(0, 0, 0, 1)">);
                String password </span><span style="color: rgba(128, 128, 128, 1)">=</span> rs.getString(<span style="color: rgba(128, 0, 0, 1); font-weight: bold">2</span><span style="color: rgba(0, 0, 0, 1)">);
                System.out.println(username </span><span style="color: rgba(128, 128, 128, 1)">+</span> ", " <span style="color: rgba(128, 128, 128, 1)">+</span><span style="color: rgba(0, 0, 0, 1)"> password);
            }
        }</span></pre>
    </div>
    <p><span style="line-height: 1.5">9、规范化代码</span></p>
    <p>所谓规范化代码就是无论是否出现异常，都要关闭ResultSet、Statement，以及Connection，如果你还记得IO流的规范化代码，那么下面的代码你就明白什么意思了。</p>
    <div class="cnblogs_code">
    <pre> <span style="color: rgba(0, 128, 0, 1)">@Test</span>
        <span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> void query() {
            Connection con </span><span style="color: rgba(128, 128, 128, 1)">=</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
            Statement stmt </span><span style="color: rgba(128, 128, 128, 1)">=</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
            ResultSet rs </span><span style="color: rgba(128, 128, 128, 1)">=</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
            try {
                con </span><span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(0, 0, 0, 1)"> getConnection();
                stmt </span><span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(0, 0, 0, 1)"> con.createStatement();
                String sql </span><span style="color: rgba(128, 128, 128, 1)">=</span> "<span style="color: rgba(0, 0, 255, 1)">select</span> <span style="color: rgba(128, 128, 128, 1)">*</span> <span style="color: rgba(0, 0, 255, 1)">from</span> <span style="color: rgba(255, 0, 255, 1)">user</span><span style="color: rgba(0, 0, 0, 1)">";
                rs </span><span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(0, 0, 0, 1)"> stmt.executeQuery(sql);
                </span><span style="color: rgba(0, 0, 255, 1)">while</span>(rs.<span style="color: rgba(0, 0, 255, 1)">next</span><span style="color: rgba(0, 0, 0, 1)">()) {
                    String username </span><span style="color: rgba(128, 128, 128, 1)">=</span> rs.getString(<span style="color: rgba(128, 0, 0, 1); font-weight: bold">1</span><span style="color: rgba(0, 0, 0, 1)">);
                    String password </span><span style="color: rgba(128, 128, 128, 1)">=</span> rs.getString(<span style="color: rgba(128, 0, 0, 1); font-weight: bold">2</span><span style="color: rgba(0, 0, 0, 1)">);
                    System.out.println(username </span><span style="color: rgba(128, 128, 128, 1)">+</span> ", " <span style="color: rgba(128, 128, 128, 1)">+</span><span style="color: rgba(0, 0, 0, 1)"> password);
                }
            } catch(Exception e) {
                throw new RuntimeException(e);
            } finally {
                try {
                    </span><span style="color: rgba(0, 0, 255, 1)">if</span>(rs <span style="color: rgba(128, 128, 128, 1)">!=</span> <span style="color: rgba(0, 0, 255, 1)">null</span>) rs.<span style="color: rgba(0, 0, 255, 1)">close</span><span style="color: rgba(0, 0, 0, 1)">();
                    </span><span style="color: rgba(0, 0, 255, 1)">if</span>(stmt <span style="color: rgba(128, 128, 128, 1)">!=</span> <span style="color: rgba(0, 0, 255, 1)">null</span>) stmt.<span style="color: rgba(0, 0, 255, 1)">close</span><span style="color: rgba(0, 0, 0, 1)">();
                    </span><span style="color: rgba(0, 0, 255, 1)">if</span>(con <span style="color: rgba(128, 128, 128, 1)">!=</span> <span style="color: rgba(0, 0, 255, 1)">null</span>) con.<span style="color: rgba(0, 0, 255, 1)">close</span><span style="color: rgba(0, 0, 0, 1)">();
                } catch(SQLException e) {}
            }
        }</span></pre>
    </div>
    <h2><span style="line-height: 1.5">JDBC对象介绍</span></h2>
    <p>JDBC中的主要类（接口）<br>在JDBC中常用的类有：&nbsp;<span class="cnblogs_code"><span style="color: rgba(0, 0, 0, 1)">DriverManager； Connection； Statement； ResultSet。</span></span>&nbsp;</p>
    <h3>DriverManager</h3>
    <p>其实我们今后只需要会用DriverManager的getConnection()方法即可：</p>
    <div class="cnblogs_code">
    <pre>Class.forName(“com.mysql.jdbc.Driver”);<span style="color: rgba(128, 128, 128, 1)">//</span><span style="color: rgba(0, 0, 0, 1)">注册驱动
    String url </span><span style="color: rgba(128, 128, 128, 1)">=</span> “jdbc:mysql:<span style="color: rgba(128, 128, 128, 1)">//</span>localhost:<span style="color: rgba(128, 0, 0, 1); font-weight: bold">3306</span><span style="color: rgba(128, 128, 128, 1)">/</span><span style="color: rgba(0, 0, 0, 1)">web08”;
    String username </span><span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(0, 0, 0, 1)"> “root”;
    String password </span><span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(0, 0, 0, 1)"> “root”;
    Connection con </span><span style="color: rgba(128, 128, 128, 1)">=</span> DriverManager.getConnection(url, username, password);</pre>
    </div>
    <p><span style="line-height: 1.5">注意，上面代码可能出现的两种异常：</span></p>
    <p>ClassNotFoundException：这个异常是在第1句上出现的，出现这个异常有两个可能：</p>
    <ul>
    <li>你没有给出mysql的jar包；</li>
    <li>你把类名称打错了，查看类名是不是com.mysql.jdbc.Driver。</li>
    </ul>
    <p>SQLException：这个异常出现在第5句，出现这个异常就是三个参数的问题，往往username和password一般不是出错，所以需要认真查看url是否打错。<br>对于DriverManager.registerDriver()方法了解即可，因为我们今后注册驱动只会Class.forName()，而不会使用这个方法。</p>
    <h3>Connection</h3>
    <p>Connection最为重要的方法就是获取Statement：</p>
    <div class="cnblogs_code">
    <pre>Statement stmt <span style="color: rgba(128, 128, 128, 1)">=</span> con.createStatement(); </pre>
    </div>
    <p><span style="line-height: 1.5">后面在学习ResultSet方法时，还要学习一下下面的方法：</span></p>
    <div class="cnblogs_code">
    <pre>Statement stmt <span style="color: rgba(128, 128, 128, 1)">=</span> con.createStatement(<span style="color: rgba(0, 0, 255, 1)">int</span>,<span style="color: rgba(0, 0, 255, 1)">int</span>);</pre>
    </div>
    <h3><span style="line-height: 1.5">Statement</span></h3>
    <p>Statement最为重要的方法是：</p>
    <pre>int executeUpdate(String sql)：执行更新操作，即执行insert、update、delete语句，其实这个方法也可以执行create table、alter table，以及drop table等语句，但我们很少会使用JDBC来执行这些语句；<br>ResultSet executeQuery(String sql)：执行查询操作，执行查询操作会返回ResultSet，即结果集。<br>boolean execute()：这个方法可以用来执行增、删、改、查所有SQL语句。该方法返回的是boolean类型，表示SQL语句是否执行成功。<br>如果使用execute()方法执行的是更新语句，那么还要调用int getUpdateCount()来获取insert、update、delete语句所影响的行数。<br>如果使用execute()方法执行的是查询语句，那么还要调用ResultSet getResultSet()来获取select语句的查询结果。</pre>
    <h3>ResultSet之滚动结果集</h3>
    <p>ResultSet表示结果集，它是一个二维的表格！ResultSet内部维护一个行光标（游标），ResultSet提供了一系列的方法来移动游标：</p>
    <pre>void beforeFirst()：把光标放到第一行的前面，这也是光标默认的位置；<br>void afterLast()：把光标放到最后一行的后面；<br>boolean first()：把光标放到第一行的位置上，返回值表示调控光标是否成功；<br>boolean last()：把光标放到最后一行的位置上；<br>boolean isBeforeFirst()：当前光标位置是否在第一行前面；<br>boolean isAfterLast()：当前光标位置是否在最后一行的后面；<br>boolean isFirst()：当前光标位置是否在第一行上；<br>boolean isLast()：当前光标位置是否在最后一行上；<br>boolean previous()：把光标向上挪一行；<br>boolean next()：把光标向下挪一行；<br>boolean relative(int row)：相对位移，当row为正数时，表示向下移动row行，为负数时表示向上移动row行；<br>boolean absolute(int row)：绝对位移，把光标移动到指定的行上；<br>int getRow()：返回当前光标所有行。</pre>
    <p>上面方法分为两类，一类用来判断游标位置的，另一类是用来移动游标的。如果结果集是不可滚动的，那么只能使用next()方法来移动游标，而beforeFirst()、afterLast()、first()、last()、previous()、relative()方法都不能使用！！！<br>结果集是否支持滚动，要从Connection类的createStatement()方法说起。也就是说创建的Statement决定了使用Statement创建的ResultSet是否支持滚动。</p>
    <div class="cnblogs_code">
    <pre>Statement createStatement(<span style="color: rgba(0, 0, 255, 1)">int</span> resultSetType, <span style="color: rgba(0, 0, 255, 1)">int</span> resultSetConcurrency)</pre>
    </div>
    <p><span style="line-height: 1.5">resultSetType的可选值：</span></p>
    <pre>ResultSet.TYPE_FORWARD_ONLY：不滚动结果集；<br>ResultSet.TYPE_SCROLL_INSENSITIVE：滚动结果集，但结果集数据不会再跟随数据库而变化；<br>ResultSet.TYPE_SCROLL_SENSITIVE：滚动结果集，但结果集数据不会再跟随数据库而变化；</pre>
    <p>可以看出，如果想使用滚动的结果集，我们应该选择TYPE_SCROLL_INSENSITIVE！其实很少有数据库驱动会支持TYPE_SCROLL_SENSITIVE的特性！通常我们也不需要查询到的结果集再受到数据库变化的影响。<br>resultSetConcurrency的可选值：</p>
    <pre>CONCUR_READ_ONLY：结果集是只读的，不能通过修改结果集而反向影响数据库；<br>CONCUR_UPDATABLE：结果集是可更新的，对结果集的更新可以反向影响数据库。通常可更新结果集这一“高级特性”我们也是不需要的！</pre>
    <p>获取滚动结果集的代码如下：</p>
    <div class="cnblogs_code">
    <pre>Connection con <span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(0, 0, 0, 1)"> …
    Statement stmt </span><span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(0, 0, 0, 1)"> con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, CONCUR_READ_ONLY);
    String sql </span><span style="color: rgba(128, 128, 128, 1)">=</span> …<span style="color: rgba(128, 128, 128, 1)">//</span><span style="color: rgba(0, 0, 0, 1)">查询语句
    ResultSet rs </span><span style="color: rgba(128, 128, 128, 1)">=</span> stmt.executeQuery(sql);<span style="color: rgba(128, 128, 128, 1)">//</span>这个结果集是可滚动的</pre>
    </div>
    <h3><span style="line-height: 1.5">ResultSet之获取列数据</span></h3>
    <p>可以通过next()方法使ResultSet的游标向下移动，当游标移动到你需要的行时，就需要来获取该行的数据了，ResultSet提供了一系列的获取列数据的方法：</p>
    <pre>String getString(int columnIndex)：获取指定列的String类型数据；<br>int getInt(int columnIndex)：获取指定列的int类型数据；<br>double getDouble(int columnIndex)：获取指定列的double类型数据；<br>boolean getBoolean(int columnIndex)：获取指定列的boolean类型数据；<br>Object getObject(int columnIndex)：获取指定列的Object类型的数据。</pre>
    <p>上面方法中，参数columnIndex表示列的索引，列索引从1开始，而不是0，这第一点与数组不同。如果你清楚当前列的数据类型，那么可以使用getInt()之类的方法来获取，如果你不清楚列的类型，那么你应该使用getObject()方法来获取。<br>ResultSet还提供了一套通过列名称来获取列数据的方法：</p>
    <pre>String getString(String columnName)：获取名称为columnName的列的String数据；<br>int getInt(String columnName)：获取名称为columnName的列的int数据；<br>double getDouble(String columnName)：获取名称为columnName的列的double数据；<br>boolean getBoolean(String columnName)：获取名称为columnName的列的boolean数据；<br>Object getObject(String columnName)：获取名称为columnName的列的Object数据；</pre>
    <h2>PreparedStatement</h2>
    <p>SQL攻击：在需要用户输入的地方，用户输入的是SQL语句的片段，最终用户输入的SQL片段与我们DAO中写的SQL语句合成一个完整的SQL语句！例如用户在登录时输入的用户名和密码都是为SQL语句的片段！</p>
    <h3>演示SQL攻击</h3>
    <p>首先我们需要创建一张用户表，用来存储用户的信息。</p>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 255, 1)">CREATE</span> <span style="color: rgba(0, 0, 255, 1)">TABLE</span> <span style="color: rgba(255, 0, 255, 1)">user</span><span style="color: rgba(0, 0, 0, 1)">(
    uid    </span><span style="color: rgba(0, 0, 255, 1)">CHAR</span>(<span style="color: rgba(128, 0, 0, 1); font-weight: bold">32</span>) <span style="color: rgba(0, 0, 255, 1)">PRIMARY</span> <span style="color: rgba(0, 0, 255, 1)">KEY</span><span style="color: rgba(0, 0, 0, 1)">,
    username    </span><span style="color: rgba(0, 0, 255, 1)">VARCHAR</span>(<span style="color: rgba(128, 0, 0, 1); font-weight: bold">30</span>) <span style="color: rgba(0, 0, 255, 1)">UNIQUE</span> <span style="color: rgba(0, 0, 255, 1)">KEY</span> <span style="color: rgba(128, 128, 128, 1)">NOT</span> <span style="color: rgba(0, 0, 255, 1)">NULL</span><span style="color: rgba(0, 0, 0, 1)">,
    PASSWORD </span><span style="color: rgba(0, 0, 255, 1)">VARCHAR</span>(<span style="color: rgba(128, 0, 0, 1); font-weight: bold">30</span><span style="color: rgba(0, 0, 0, 1)">)
    );
    
    </span><span style="color: rgba(0, 0, 255, 1)">INSERT</span> <span style="color: rgba(0, 0, 255, 1)">INTO</span> <span style="color: rgba(255, 0, 255, 1)">user</span> <span style="color: rgba(0, 0, 255, 1)">VALUES</span>(<span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(255, 0, 0, 1)">U_1001</span><span style="color: rgba(255, 0, 0, 1)">'</span>, <span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(255, 0, 0, 1)">zs</span><span style="color: rgba(255, 0, 0, 1)">'</span>, <span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(255, 0, 0, 1)">zs</span><span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">);
    </span><span style="color: rgba(0, 0, 255, 1)">SELECT</span> <span style="color: rgba(128, 128, 128, 1)">*</span> <span style="color: rgba(0, 0, 255, 1)">FROM</span> <span style="color: rgba(255, 0, 255, 1)">user</span>;</pre>
    </div>
    <p><span style="line-height: 1.5">现在用户表中只有一行记录，就是zs。</span></p>
    <p>下面我们写一个login()方法！</p>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> void login(String username, String password) {
            Connection con </span><span style="color: rgba(128, 128, 128, 1)">=</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
            Statement stmt </span><span style="color: rgba(128, 128, 128, 1)">=</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
            ResultSet rs </span><span style="color: rgba(128, 128, 128, 1)">=</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
            try {
                con </span><span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(0, 0, 0, 1)"> JdbcUtils.getConnection();
                stmt </span><span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(0, 0, 0, 1)"> con.createStatement();
                String sql </span><span style="color: rgba(128, 128, 128, 1)">=</span> "<span style="color: rgba(0, 0, 255, 1)">SELECT</span> <span style="color: rgba(128, 128, 128, 1)">*</span> <span style="color: rgba(0, 0, 255, 1)">FROM</span> <span style="color: rgba(255, 0, 255, 1)">user</span> <span style="color: rgba(0, 0, 255, 1)">WHERE</span> " <span style="color: rgba(128, 128, 128, 1)">+</span><span style="color: rgba(0, 0, 0, 1)">
                        "username</span><span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(255, 0, 0, 1)">" + username +
                        "</span><span style="color: rgba(255, 0, 0, 1)">'</span> <span style="color: rgba(128, 128, 128, 1)">and</span> password<span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(255, 0, 0, 1)">" + password + "</span><span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">";
                rs </span><span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(0, 0, 0, 1)"> stmt.executeQuery(sql);
                </span><span style="color: rgba(0, 0, 255, 1)">if</span>(rs.<span style="color: rgba(0, 0, 255, 1)">next</span><span style="color: rgba(0, 0, 0, 1)">()) {
                    System.out.println("欢迎" </span><span style="color: rgba(128, 128, 128, 1)">+</span><span style="color: rgba(0, 0, 0, 1)"> rs.getString("username"));
                } </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
                    System.out.println("用户名或密码错误！");
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                JdbcUtils.</span><span style="color: rgba(0, 0, 255, 1)">close</span><span style="color: rgba(0, 0, 0, 1)">(con, stmt, rs);
            }
        }</span></pre>
    </div>
    <p><span style="line-height: 1.5">下面是调用这个方法的代码：</span></p>
    <div class="cnblogs_code">
    <pre>login("a<span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(255, 0, 0, 1)"> or </span><span style="color: rgba(255, 0, 0, 1)">'</span>a<span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(255, 0, 0, 1)">=</span><span style="color: rgba(255, 0, 0, 1)">'</span>a", "a<span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(255, 0, 0, 1)"> or </span><span style="color: rgba(255, 0, 0, 1)">'</span>a<span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(255, 0, 0, 1)">=</span><span style="color: rgba(255, 0, 0, 1)">'</span>a");</pre>
    </div>
    <p><span style="line-height: 1.5">这行当前会使我们登录成功！因为是输入的用户名和密码是SQL语句片段，最终与我们的login()方法中的SQL语句组合在一起！我们来看看组合在一起的SQL语句：</span></p>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 255, 1)">SELECT</span> <span style="color: rgba(128, 128, 128, 1)">*</span> <span style="color: rgba(0, 0, 255, 1)">FROM</span> tab_user <span style="color: rgba(0, 0, 255, 1)">WHERE</span> username<span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(255, 0, 0, 1)">a</span><span style="color: rgba(255, 0, 0, 1)">'</span> <span style="color: rgba(128, 128, 128, 1)">or</span> <span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(255, 0, 0, 1)">a</span><span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(255, 0, 0, 1)">a</span><span style="color: rgba(255, 0, 0, 1)">'</span> <span style="color: rgba(128, 128, 128, 1)">and</span> password<span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(255, 0, 0, 1)">a</span><span style="color: rgba(255, 0, 0, 1)">'</span> <span style="color: rgba(128, 128, 128, 1)">or</span> <span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(255, 0, 0, 1)">a</span><span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(255, 0, 0, 1)">'</span><span style="color: rgba(255, 0, 0, 1)">a</span><span style="color: rgba(255, 0, 0, 1)">'</span></pre>
    </div>
    <h3><span style="line-height: 1.5">防止SQL攻击</span></h3>
    <ul>
    <li>过滤用户输入的数据中是否包含非法字符；</li>
    <li>分步校验！先使用用户名来查询用户，如果查找到了，再比较密码；</li>
    <li>使用PreparedStatement。</li>
    </ul>
    <p>PreparedStatement是什么？PreparedStatement叫预编译声明！PreparedStatement是Statement的子接口，你可以使用PreparedStatement来替换Statement。<br>PreparedStatement的好处：</p>
    <ul>
    <li>防止SQL攻击；</li>
    <li>提高代码的可读性，以可维护性；</li>
    <li>提高效率。</li>
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    </ul>
    <p>PreparedStatement的使用</p>
    <pre>使用Connection的prepareStatement(String sql)：即创建它时就让它与一条SQL模板绑定；<br>调用PreparedStatement的setXXX()系列方法为问号设置值<br>调用executeUpdate()或executeQuery()方法，但要注意，调用没有参数的方法；</pre>
    <div class="cnblogs_code">
    <pre>String sql <span style="color: rgba(128, 128, 128, 1)">=</span> “<span style="color: rgba(0, 0, 255, 1)">select</span> <span style="color: rgba(128, 128, 128, 1)">*</span> <span style="color: rgba(0, 0, 255, 1)">from</span> tab_student <span style="color: rgba(0, 0, 255, 1)">where</span> s_number<span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(0, 0, 0, 1)">?”;
    PreparedStatement pstmt </span><span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(0, 0, 0, 1)"> con.prepareStatement(sql);
    pstmt.setString(</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">1</span><span style="color: rgba(0, 0, 0, 1)">, “S_1001”);
    ResultSet rs </span><span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(0, 0, 0, 1)"> pstmt.executeQuery();
    rs.</span><span style="color: rgba(0, 0, 255, 1)">close</span><span style="color: rgba(0, 0, 0, 1)">();
    pstmt.clearParameters();
    pstmt.setString(</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">1</span><span style="color: rgba(0, 0, 0, 1)">, “S_1002”);
    rs </span><span style="color: rgba(128, 128, 128, 1)">=</span> pstmt.executeQuery();</pre>
    </div>
    <p><span style="line-height: 1.5">在使用Connection创建PreparedStatement对象时需要给出一个SQL模板，所谓SQL模板就是有“?”的SQL语句，其中“?”就是参数。</span></p>
    <p>在得到PreparedStatement对象后，调用它的setXXX()方法为“?”赋值，这样就可以得到把模板变成一条完整的SQL语句，然后再调用PreparedStatement对象的executeQuery()方法获取ResultSet对象。<br>注意PreparedStatement对象独有的executeQuery()方法是没有参数的，而Statement的executeQuery()是需要参数（SQL语句）的。因为在创建PreparedStatement对象时已经让它与一条SQL模板绑定在一起了，所以在调用它的executeQuery()和executeUpdate()方法时就不再需要参数了。<br>PreparedStatement最大的好处就是在于重复使用同一模板，给予其不同的参数来重复的使用它。这才是真正提高效率的原因。所以，建议在今后的开发中，无论什么情况，都去需要PreparedStatement，而不是使用Statement。</p>
    <p>详情参考<a href="http://www.cnblogs.com/wuyuegb2312/p/3872607.html" target="_blank">这里</a></p>
    <h2>使用<a href="http://blog.csdn.net/sakura_yuan/article/details/51730493">&nbsp;</a>intelliJ IDEA 查询数据</h2>
    <p>第一步：新建一个项目</p>
    <p><img src="https://images2015.cnblogs.com/blog/612774/201707/612774-20170702202734586-416048448.png" alt=""></p>
    <p>第二步：Next &gt; 选择Java Hello World &gt; Next&nbsp;</p>
    <p><img src="https://images2015.cnblogs.com/blog/612774/201707/612774-20170702202841539-785535405.png" alt=""></p>
    <p>第三步：输入项目名称，然后finish</p>
    <p><img src="https://images2015.cnblogs.com/blog/612774/201707/612774-20170702202943524-1955780508.png" alt=""></p>
    <p>第四步：修改Main文件名为JdbcDemo</p>
    <p>&nbsp;<img src="https://images2015.cnblogs.com/blog/612774/201707/612774-20170702203141914-1573862736.png" alt=""></p>
    <p>第五步：导入jar包</p>
    <p>jdbc下载地址：https://dev.mysql.com/downloads/connector/j/5.1.html</p>
    <p><img src="https://images2015.cnblogs.com/blog/612774/201707/612774-20170702203337727-1808407936.png" alt=""></p>
    <p><img src="https://images2015.cnblogs.com/blog/612774/201707/612774-20170702203501508-1624742340.png" alt=""></p>
    <p>找到刚下载的jar包</p>
    <p><img src="https://images2015.cnblogs.com/blog/612774/201707/612774-20170702203638555-2055339056.png" alt=""></p>
    <p>添加后可以看到如下jar包，表示成功。</p>
    <p><img src="https://images2015.cnblogs.com/blog/612774/201707/612774-20170702203725649-1433217281.png" alt=""></p>
    <p>编写java代码，JdbcDemo.java</p>
    <div class="cnblogs_code">
    <pre>import java.sql.<span style="color: rgba(128, 128, 128, 1)">*</span><span style="color: rgba(0, 0, 0, 1)">;
    
    </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> class JdbcDemo {
    
        </span><span style="color: rgba(0, 0, 255, 1)">public</span> static void main(String<span style="color: rgba(255, 0, 0, 1)">[]</span><span style="color: rgba(0, 0, 0, 1)"> args) {
            query();
        }
        </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> static Connection getConnection() throws Exception {
            Class.forName("com.mysql.jdbc.Driver");
            String url </span><span style="color: rgba(128, 128, 128, 1)">=</span> "jdbc:mysql:<span style="color: rgba(128, 128, 128, 1)">//</span>localhost:<span style="color: rgba(128, 0, 0, 1); font-weight: bold">3306</span><span style="color: rgba(128, 128, 128, 1)">/</span><span style="color: rgba(0, 0, 0, 1)">test";
            </span><span style="color: rgba(0, 0, 255, 1)">return</span> DriverManager.getConnection(url, "root", "<span style="color: rgba(128, 0, 0, 1); font-weight: bold">123456</span><span style="color: rgba(0, 0, 0, 1)">");
        }
        </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> static void query() {
            Connection con </span><span style="color: rgba(128, 128, 128, 1)">=</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
            Statement stmt </span><span style="color: rgba(128, 128, 128, 1)">=</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
            ResultSet rs </span><span style="color: rgba(128, 128, 128, 1)">=</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
            try {
                con </span><span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(0, 0, 0, 1)"> getConnection();
                stmt </span><span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(0, 0, 0, 1)"> con.createStatement();
                String sql </span><span style="color: rgba(128, 128, 128, 1)">=</span> "<span style="color: rgba(0, 0, 255, 1)">select</span> <span style="color: rgba(128, 128, 128, 1)">*</span> <span style="color: rgba(0, 0, 255, 1)">from</span> <span style="color: rgba(255, 0, 255, 1)">user</span><span style="color: rgba(0, 0, 0, 1)">";
                rs </span><span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(0, 0, 0, 1)"> stmt.executeQuery(sql);
                </span><span style="color: rgba(0, 0, 255, 1)">while</span>(rs.<span style="color: rgba(0, 0, 255, 1)">next</span><span style="color: rgba(0, 0, 0, 1)">()) {
                    String id </span><span style="color: rgba(128, 128, 128, 1)">=</span> rs.getString(<span style="color: rgba(128, 0, 0, 1); font-weight: bold">1</span><span style="color: rgba(0, 0, 0, 1)">);
                    String password </span><span style="color: rgba(128, 128, 128, 1)">=</span> rs.getString(<span style="color: rgba(128, 0, 0, 1); font-weight: bold">2</span><span style="color: rgba(0, 0, 0, 1)">);
                    String username </span><span style="color: rgba(128, 128, 128, 1)">=</span> rs.getString(<span style="color: rgba(128, 0, 0, 1); font-weight: bold">3</span><span style="color: rgba(0, 0, 0, 1)">);
                    String info </span><span style="color: rgba(128, 128, 128, 1)">=</span> rs.getString(<span style="color: rgba(128, 0, 0, 1); font-weight: bold">4</span><span style="color: rgba(0, 0, 0, 1)">);
                    System.out.println( id</span><span style="color: rgba(128, 128, 128, 1)">+</span> ", " <span style="color: rgba(128, 128, 128, 1)">+</span> username<span style="color: rgba(128, 128, 128, 1)">+</span> ", " <span style="color: rgba(128, 128, 128, 1)">+</span> password<span style="color: rgba(128, 128, 128, 1)">+</span> ", " <span style="color: rgba(128, 128, 128, 1)">+</span><span style="color: rgba(0, 0, 0, 1)"> info);
                }
            } catch(Exception e) {
                throw new RuntimeException(e);
            } finally {
                try {
                    </span><span style="color: rgba(0, 0, 255, 1)">if</span>(rs <span style="color: rgba(128, 128, 128, 1)">!=</span> <span style="color: rgba(0, 0, 255, 1)">null</span>) rs.<span style="color: rgba(0, 0, 255, 1)">close</span><span style="color: rgba(0, 0, 0, 1)">();
                    </span><span style="color: rgba(0, 0, 255, 1)">if</span>(stmt <span style="color: rgba(128, 128, 128, 1)">!=</span> <span style="color: rgba(0, 0, 255, 1)">null</span>) stmt.<span style="color: rgba(0, 0, 255, 1)">close</span><span style="color: rgba(0, 0, 0, 1)">();
                    </span><span style="color: rgba(0, 0, 255, 1)">if</span>(con <span style="color: rgba(128, 128, 128, 1)">!=</span> <span style="color: rgba(0, 0, 255, 1)">null</span>) con.<span style="color: rgba(0, 0, 255, 1)">close</span><span style="color: rgba(0, 0, 0, 1)">();
                } catch(SQLException e) {}
            }
        }
    }</span></pre>
    </div>
    <p>创建test数据库，然后创建user表，表结构如下，然后添加一些数据。</p>
    <p><img src="https://images2015.cnblogs.com/blog/612774/201707/612774-20170702204334305-856928211.png" alt=""></p>
    <p>运行java代码，获取结果：</p>
    <p>&nbsp;<img src="https://images2015.cnblogs.com/blog/612774/201707/612774-20170702204447352-650878506.png" alt=""></p>
    <p>&nbsp;</p>
    </div>

</body>
</html>